In this notebook, I’ll …
- … download data from the “Song of Ice and Fire API”, https://anapioficeandfire.com/. A web API is a way to download data from the internet. The asoif API is a repository that contains a lot of GOT related data.
- … make data transformations to ready data for analysis
- … examine two research questions and create appropriate visualizations and analysis on the data
# Load packages
library(tidyverse)
library(magrittr)
library(httr)
library(forcats)
library(tidytext)
library(wordcloud2)
library(stringr)
library(ggridges)
First we have to download the data from the web. This API is “paginated”, which means that the data can be downloaded as it was a homepage with a fixed page size (e.g. 50 book characters in a page), and you have access to ‘next’ and ‘previous’ button links. So we need to build a loop to collect data from all characters.
# A loop to get paginated responses from ASOIAF API
page <- 1
newpage <- httr::GET(paste0("https://www.anapioficeandfire.com/api/characters?page=", page,"&pageSize=50"), accept_json())
got_content <- newpage %>% content()
while(headers(newpage)$link %>% grepl("rel=\"next\"", .))
# Collect data until `next` link disappear
{
page <- page + 1
newpage <-
httr::GET(paste0("https://www.anapioficeandfire.com/api/characters?page=",page,"&pageSize=50"),
accept_json()
)
got_content %<>% append(content(newpage))
cat("=")
}
==========================================
length(got_content)
[1] 2134
We collected a whooping 2134 characters from the Game of Thrones universe!
In the next block, we transform the data from the awkward hierarchical data structure into a data frame, that is easy to use. We also clean the data to get meaningful variables.
# Put list data into nested data frame
got_chars_df <-
got_content %>%
tibble( # Create an analyzable data frame from the complex list object
url = map_chr(., "url"),
name = map_chr(., "name"),
gender = map_chr(., "gender"),
culture = map_chr(., "culture"),
born = map_chr(., "born"),
died = map_chr(., "died"),
titles = map(., "titles"),
aliases = map(., "aliases"),
father = map_chr(., "father"),
mother = map_chr(., "mother"),
spouse = map_chr(., "spouse"),
allegiances = map(., "allegiances"),
books = map(., "books"),
povBooks = map(., "povBooks"),
tvSeries = map(., "tvSeries"),
playedBy = map(., "playedBy")
) %>%
mutate_if(is.character,funs(if_else(trimws(.) == "",NA_character_, .))) %>% # Explicit NA
rowwise() %>%
mutate(
alias_length = length(aliases), # How many aliases does the person have
alias_names = unlist(aliases) %>% paste(collapse = ", "), # Collapse aliases to one string
has_spouse = if_else(!is.na(spouse), TRUE, FALSE), # Have a spouse?
birth_year = str_extract(born, " \\d* ") %>% as.numeric(), # Extract birthyear
death_year = str_extract(died, " \\d* ") %>% as.numeric(), # Extract deathyear
is_alive = if_else(is.na(died) & 300 - birth_year < 100, TRUE, FALSE), # Alive?
age = if_else(is_alive, 300 - birth_year, death_year - birth_year)) %>% # Age (or age when died)
arrange(name)
head(got_chars_df)
Analysis question 1: What offensive aliases the GOT characters have? Who has the most offensive ones?
Game of thrones characters have many nicknames, that are often used. We are going to mine these names and check if these words have negative or positive connotation.
In order to do this, we are getting aliases and assign sentiment values for them. But first, let’s see who has the most names.
# Preparing data for analysis on aliases
long_names <-
got_chars_df %>%
select(name, alias_length, alias_names) %>%
unnest_tokens(word, alias_names) %>% # Create a word-wise tidy dataset
left_join(get_sentiments("bing"), by = "word") %>% # Add a sentiment dictionary
rowwise() %>%
filter(!grepl(word, str_to_lower(name))) # Remove oiginal names from the alias
# Who has the most aliases? (showing the ones (with at least 5 aliases)
long_names %>%
filter(alias_length >= 5) %>%
ggplot() +
aes(y = alias_length, x = fct_reorder(name, alias_length)) +
geom_col(position = "dodge") +
scale_x_discrete() +
coord_flip() +
labs(y = "Number of aliases", x = "Name") +
ggtitle("Characters with the most aliases (al least 5)")

# Create a wordcloud of the aliases
long_names %>%
anti_join(stop_words, by = "word") %>% # Remove stopwords
group_by(word) %>%
count() %>%
wordcloud2()
# Show the character alias sentiments
long_names %>%
anti_join(stop_words, by = "word") %>%
drop_na(sentiment) %>%
group_by(name, sentiment) %>%
summarise(full_alias = paste(word, collapse = " "),
alias_length = first(alias_length),
sentiment_n = n()) %>%
filter(sentiment_n>1) %>%
arrange(-alias_length) %>%
ggplot() +
aes(x = fct_reorder(name, sentiment_n), y = sentiment_n, fill = sentiment, label = full_alias) +
geom_col() +
geom_text(hjust = 1) +
coord_flip() +
labs(y = "Number of aliases with sentiment", x = "Name") +
ggtitle("Sentiment of the aliases by name")

So, we can conclude that the Tyrion Lennister, Ramsey Snow, Jon Snow, and Brandon Stark has the most aliases with negative connotations. Honestly I think that the standard sentiment library is not perfectly suitable for this job as it does not contain sentiments for “king slayer”, “silver tongue”, or “horse face”. So a more suitable sentiment library should be used to improve the accuracy of this analysis.
Analysis question 2: Exploring survival chance of got characters
Based on the data of 585 characters whose death was documented in got, it seems like males have a higher higher age at death (mean = 36.5, SD = 22.7) than females (mean = 28.2 SD = 16.5). Not that high. Also, males expected age of death is based on almost 5 times as many observations.
got_chars_df %>%
filter(!is_alive) %>%
group_by(gender) %>%
summarise(Mean = mean(age, na.rm = T) %>% round(1),
Sd = sd(age, na.rm = T) %>% round(1),
N = n())
got_chars_df %>%
filter(!is_alive) %>%
ggplot() +
aes(x = age, y = gender, fill = gender) +
geom_density_ridges(alpha = .7)

So how dangerous is a marriage in GOT?
People die left and right in game of thrones, but no occasion is as deadly as a good wedding. But what about marriage? How people fare if they survived their wedding? In real life, lifetime expectancy is increased by marriage, which is obviously not the case in Game of Thrones. But exactly how dangerous is to be married in GOT?
We are building a logistic binomial regression on got character data with the outcome variable that shows if the character is alive or not. We restrict the analysis to characters that were born within a 102 years (This is the age of oldest character that dies in the books) because we want to focus on the book’s story-line. We are only looking for main effects of age, gender, and marital status (if the character has a spouse). Disclaimer: This is obviously a very simple minded analysis, and I only did that to show how this kind of stuff can be done in R.
got_chars_df %>%
filter(birth_year >=198) %>% # Restrict analysis to recent events in got (last 102 years)
select(is_alive, has_spouse, gender) %>%
ftable()
gender Female Male
is_alive has_spouse
FALSE FALSE 15 48
TRUE 13 27
TRUE FALSE 79 143
TRUE 32 29
The data is based on 386 characters, with the characteristics above. To explore data, we create a box plot visualization about age by gender by marital status by survival status.
got_chars_df %>%
filter(birth_year >=198) %>% # Restrict analysis to recent events in got (last 102 years)
ggplot() +
aes(y = age, x = gender, fill = gender) +
geom_boxplot() +
facet_grid(is_alive~has_spouse, labeller = label_both)

Now we create a statistical model (binomial logistic) to test the effect of the predictors on the outcome variable (survival status).
survival_model <-
got_chars_df %>%
filter(birth_year >=198) %>%
glm(is_alive ~ age + has_spouse + gender, family = "binomial", data = .)
survival_model %>% summary
Call:
glm(formula = is_alive ~ age + has_spouse + gender, family = "binomial",
data = .)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.0549 -1.1724 0.6902 0.7864 1.2898
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.990591 0.280269 7.102 1.23e-12 ***
age -0.008283 0.005992 -1.382 0.16687
has_spouseTRUE -0.869603 0.268282 -3.241 0.00119 **
genderMale -0.619333 0.275081 -2.251 0.02436 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 434.44 on 380 degrees of freedom
Residual deviance: 413.35 on 377 degrees of freedom
(5 observations deleted due to missingness)
AIC: 421.35
Number of Fisher Scoring iterations: 4
Makeshift conclusions:
- We looked at dying in the last 102 years, so we excluded characters who died long before the story-line
- Age is not a significant predictor for dying, so people of all ages perish left and right
- Males have a worse survival chance (they are twice as likely to die in the books’ story-line). This is the opposite to the previous finding because here we only focused on recent events that seem to affect male life expectancy more.
- Marriage is quite dangerous in GOT, the survival rate of married people is less than half of unmarried ones.
We also calculate odds ratios, and confidence intervals for those for visualization of effects.
survival_or <-
exp(cbind(coef(survival_model), confint(survival_model))) %>%
round(2) %>%
broom::tidy() %>%
set_names(c("variable", "OR","2.5% CI","97.5% CI"))
survival_or %>%
ggplot() +
aes(x = OR, y = fct_rev(variable), xmin = `2.5% CI`, xmax = `97.5% CI`, label = OR) +
geom_label(aes(x = 0)) +
geom_errorbarh(height = 0) +
geom_point() +
geom_vline(aes(xintercept = 1), color = "red", linetype = "dashed") +
coord_cartesian(c(0,7.5)) +
labs(x = "Odds ratio (95% CI)", y = NULL) +
ggtitle("Odds ratios for variables that predict survival in got")

And finally, let’s plot the predictions for the survival chance over time by marital status and gender.
survival_model %>%
broom::augment(type.predict = "response") %>%
ggplot() +
aes(x = age, y = .fitted, group = has_spouse, ymin = .fitted - .se.fit, ymax = .fitted + .se.fit) +
geom_ribbon(fill = "grey", alpha = .3) +
facet_wrap(~gender) +
geom_step(aes(color = has_spouse), size = 1.2) +
labs(x = "Age",
y = "Predicted survival chance (OR)",
title = "Predicted survival chance as a function of age, gender, and marital status in Game of Thrones,\nduring the storyline of the books")

LS0tDQp0aXRsZTogIkFuYWx5c2lzIG9uIEdhbWUgb2YgVGhyb25lcyBjaGFyYWN0ZXIgbmFtZXMgYW5kIG1hcnJpYWdlIHN1cnZpdmFsIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazogDQogICAgdGhlbWU6IGpvdXJuYWwNCi0tLQ0KDQpJbiB0aGlzIG5vdGVib29rLCBJJ2xsIC4uLg0KDQotIC4uLiBkb3dubG9hZCBkYXRhIGZyb20gdGhlICJTb25nIG9mIEljZSBhbmQgRmlyZSBBUEkiLCBodHRwczovL2FuYXBpb2ZpY2VhbmRmaXJlLmNvbS8uIEEgd2ViIEFQSSBpcyBhIHdheSB0byBkb3dubG9hZCBkYXRhIGZyb20gdGhlIGludGVybmV0LiBUaGUgYXNvaWYgQVBJIGlzIGEgcmVwb3NpdG9yeSB0aGF0IGNvbnRhaW5zIGEgbG90IG9mIEdPVCByZWxhdGVkIGRhdGEuDQotIC4uLiBtYWtlIGRhdGEgdHJhbnNmb3JtYXRpb25zIHRvIHJlYWR5IGRhdGEgZm9yIGFuYWx5c2lzDQotIC4uLiBleGFtaW5lIHR3byByZXNlYXJjaCBxdWVzdGlvbnMgYW5kIGNyZWF0ZSBhcHByb3ByaWF0ZSB2aXN1YWxpemF0aW9ucyBhbmQgYW5hbHlzaXMgb24gdGhlIGRhdGENCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgTG9hZCBwYWNrYWdlcw0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KbGlicmFyeShodHRyKQ0KbGlicmFyeShmb3JjYXRzKQ0KbGlicmFyeSh0aWR5dGV4dCkNCmxpYnJhcnkod29yZGNsb3VkMikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkoZ2dyaWRnZXMpDQpgYGANCg0KRmlyc3Qgd2UgaGF2ZSB0byBkb3dubG9hZCB0aGUgZGF0YSBmcm9tIHRoZSB3ZWIuIFRoaXMgQVBJIGlzICJwYWdpbmF0ZWQiLCB3aGljaCBtZWFucyB0aGF0IHRoZSBkYXRhIGNhbiBiZSBkb3dubG9hZGVkIGFzIGl0IHdhcyBhIGhvbWVwYWdlIHdpdGggYSBmaXhlZCBwYWdlIHNpemUgKGUuZy4gNTAgYm9vayBjaGFyYWN0ZXJzIGluIGEgcGFnZSksIGFuZCB5b3UgaGF2ZSBhY2Nlc3MgdG8gJ25leHQnIGFuZCAncHJldmlvdXMnIGJ1dHRvbiBsaW5rcy4gU28gd2UgbmVlZCB0byBidWlsZCBhIGxvb3AgdG8gY29sbGVjdCBkYXRhIGZyb20gYWxsIGNoYXJhY3RlcnMuDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KDQojIEEgbG9vcCB0byBnZXQgcGFnaW5hdGVkIHJlc3BvbnNlcyBmcm9tIEFTT0lBRiBBUEkNCnBhZ2UgPC0gMQ0KbmV3cGFnZSA8LSBodHRyOjpHRVQocGFzdGUwKCJodHRwczovL3d3dy5hbmFwaW9maWNlYW5kZmlyZS5jb20vYXBpL2NoYXJhY3RlcnM/cGFnZT0iLCBwYWdlLCImcGFnZVNpemU9NTAiKSwgYWNjZXB0X2pzb24oKSkNCmdvdF9jb250ZW50IDwtIG5ld3BhZ2UgJT4lIGNvbnRlbnQoKQ0KDQp3aGlsZShoZWFkZXJzKG5ld3BhZ2UpJGxpbmsgJT4lIGdyZXBsKCJyZWw9XCJuZXh0XCIiLCAuKSkNCiAgIyBDb2xsZWN0IGRhdGEgdW50aWwgYG5leHRgIGxpbmsgZGlzYXBwZWFyDQp7DQogIHBhZ2UgPC0gcGFnZSArIDENCiAgbmV3cGFnZSA8LQ0KICAgIGh0dHI6OkdFVChwYXN0ZTAoImh0dHBzOi8vd3d3LmFuYXBpb2ZpY2VhbmRmaXJlLmNvbS9hcGkvY2hhcmFjdGVycz9wYWdlPSIscGFnZSwiJnBhZ2VTaXplPTUwIiksDQogICAgICBhY2NlcHRfanNvbigpDQogICAgKQ0KICBnb3RfY29udGVudCAlPD4lIGFwcGVuZChjb250ZW50KG5ld3BhZ2UpKQ0KICBjYXQoIj0iKQ0KfQ0KDQpsZW5ndGgoZ290X2NvbnRlbnQpDQoNCmBgYA0KDQpXZSBjb2xsZWN0ZWQgYSB3aG9vcGluZyAyMTM0IGNoYXJhY3RlcnMgZnJvbSB0aGUgR2FtZSBvZiBUaHJvbmVzIHVuaXZlcnNlIQ0KDQpJbiB0aGUgbmV4dCBibG9jaywgd2UgdHJhbnNmb3JtIHRoZSBkYXRhIGZyb20gdGhlIGF3a3dhcmQgaGllcmFyY2hpY2FsIGRhdGEgc3RydWN0dXJlIGludG8gYSBkYXRhIGZyYW1lLCB0aGF0IGlzIGVhc3kgdG8gdXNlLiBXZSBhbHNvIGNsZWFuIHRoZSBkYXRhIHRvIGdldCBtZWFuaW5nZnVsIHZhcmlhYmxlcy4gDQoNCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1UUlVFfQ0KIyBQdXQgbGlzdCBkYXRhIGludG8gbmVzdGVkIGRhdGEgZnJhbWUNCmdvdF9jaGFyc19kZiA8LQ0KICBnb3RfY29udGVudCAlPiUNCiAgdGliYmxlKCAjIENyZWF0ZSBhbiBhbmFseXphYmxlIGRhdGEgZnJhbWUgZnJvbSB0aGUgY29tcGxleCBsaXN0IG9iamVjdA0KICAgIHVybCA9IG1hcF9jaHIoLiwgInVybCIpLA0KICAgIG5hbWUgPSBtYXBfY2hyKC4sICJuYW1lIiksDQogICAgZ2VuZGVyID0gbWFwX2NociguLCAiZ2VuZGVyIiksDQogICAgY3VsdHVyZSA9IG1hcF9jaHIoLiwgImN1bHR1cmUiKSwNCiAgICBib3JuID0gbWFwX2NociguLCAiYm9ybiIpLA0KICAgIGRpZWQgPSBtYXBfY2hyKC4sICJkaWVkIiksDQogICAgdGl0bGVzID0gbWFwKC4sICJ0aXRsZXMiKSwNCiAgICBhbGlhc2VzID0gbWFwKC4sICJhbGlhc2VzIiksDQogICAgZmF0aGVyID0gbWFwX2NociguLCAiZmF0aGVyIiksDQogICAgbW90aGVyID0gbWFwX2NociguLCAibW90aGVyIiksDQogICAgc3BvdXNlID0gbWFwX2NociguLCAic3BvdXNlIiksDQogICAgYWxsZWdpYW5jZXMgPSBtYXAoLiwgImFsbGVnaWFuY2VzIiksDQogICAgYm9va3MgPSBtYXAoLiwgImJvb2tzIiksDQogICAgcG92Qm9va3MgPSBtYXAoLiwgInBvdkJvb2tzIiksDQogICAgdHZTZXJpZXMgPSBtYXAoLiwgInR2U2VyaWVzIiksDQogICAgcGxheWVkQnkgPSBtYXAoLiwgInBsYXllZEJ5IikNCiAgKSAlPiUgDQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsZnVucyhpZl9lbHNlKHRyaW13cyguKSA9PSAiIixOQV9jaGFyYWN0ZXJfLCAuKSkpICU+JSAjIEV4cGxpY2l0IE5BDQogIHJvd3dpc2UoKSAlPiUgDQogIG11dGF0ZSgNCiAgICAgICAgIGFsaWFzX2xlbmd0aCA9IGxlbmd0aChhbGlhc2VzKSwgIyBIb3cgbWFueSBhbGlhc2VzIGRvZXMgdGhlIHBlcnNvbiBoYXZlDQogICAgICAgICBhbGlhc19uYW1lcyA9IHVubGlzdChhbGlhc2VzKSAlPiUgcGFzdGUoY29sbGFwc2UgPSAiLCAiKSwgIyBDb2xsYXBzZSBhbGlhc2VzIHRvIG9uZSBzdHJpbmcNCiAgICAgICAgIGhhc19zcG91c2UgPSBpZl9lbHNlKCFpcy5uYShzcG91c2UpLCBUUlVFLCBGQUxTRSksICMgSGF2ZSBhIHNwb3VzZT8NCiAgICAgICAgIGJpcnRoX3llYXIgPSBzdHJfZXh0cmFjdChib3JuLCAiIFxcZCogIikgJT4lIGFzLm51bWVyaWMoKSwgIyBFeHRyYWN0IGJpcnRoeWVhcg0KICAgICAgICAgZGVhdGhfeWVhciA9IHN0cl9leHRyYWN0KGRpZWQsICIgXFxkKiAiKSAlPiUgYXMubnVtZXJpYygpLCAjIEV4dHJhY3QgZGVhdGh5ZWFyDQogICAgICAgICBpc19hbGl2ZSA9IGlmX2Vsc2UoaXMubmEoZGllZCkgJiAzMDAgLSBiaXJ0aF95ZWFyIDwgMTAwLCBUUlVFLCBGQUxTRSksICMgQWxpdmU/DQogICAgICAgICBhZ2UgPSBpZl9lbHNlKGlzX2FsaXZlLCAzMDAgLSBiaXJ0aF95ZWFyLCBkZWF0aF95ZWFyIC0gYmlydGhfeWVhcikpICU+JSAjIEFnZSAob3IgYWdlIHdoZW4gZGllZCkNCiAgYXJyYW5nZShuYW1lKQ0KYGBgDQoNCg0KYGBge3J9DQpoZWFkKGdvdF9jaGFyc19kZikNCmBgYA0KDQoNCiMgQW5hbHlzaXMgcXVlc3Rpb24gMTogV2hhdCBvZmZlbnNpdmUgYWxpYXNlcyB0aGUgR09UIGNoYXJhY3RlcnMgaGF2ZT8gV2hvIGhhcyB0aGUgbW9zdCBvZmZlbnNpdmUgb25lcz8NCg0KR2FtZSBvZiB0aHJvbmVzIGNoYXJhY3RlcnMgaGF2ZSBtYW55IG5pY2tuYW1lcywgdGhhdCBhcmUgb2Z0ZW4gdXNlZC4gV2UgYXJlIGdvaW5nIHRvIG1pbmUgdGhlc2UgbmFtZXMgYW5kIGNoZWNrIGlmIHRoZXNlIHdvcmRzIGhhdmUgbmVnYXRpdmUgb3IgcG9zaXRpdmUgY29ubm90YXRpb24uIA0KDQpJbiBvcmRlciB0byBkbyB0aGlzLCB3ZSBhcmUgZ2V0dGluZyBhbGlhc2VzIGFuZCBhc3NpZ24gc2VudGltZW50IHZhbHVlcyBmb3IgdGhlbS4gQnV0IGZpcnN0LCBsZXQncyBzZWUgd2hvIGhhcyB0aGUgbW9zdCBuYW1lcy4NCg0KYGBge3J9DQojIFByZXBhcmluZyBkYXRhIGZvciBhbmFseXNpcyBvbiBhbGlhc2VzDQpsb25nX25hbWVzIDwtDQogIGdvdF9jaGFyc19kZiAlPiUgDQogICAgc2VsZWN0KG5hbWUsIGFsaWFzX2xlbmd0aCwgYWxpYXNfbmFtZXMpICU+JQ0KICAgIHVubmVzdF90b2tlbnMod29yZCwgYWxpYXNfbmFtZXMpICU+JSAjIENyZWF0ZSBhIHdvcmQtd2lzZSB0aWR5IGRhdGFzZXQNCiAgICBsZWZ0X2pvaW4oZ2V0X3NlbnRpbWVudHMoImJpbmciKSwgYnkgPSAid29yZCIpICU+JSAjIEFkZCBhIHNlbnRpbWVudCBkaWN0aW9uYXJ5DQogICAgcm93d2lzZSgpICU+JSANCiAgICBmaWx0ZXIoIWdyZXBsKHdvcmQsIHN0cl90b19sb3dlcihuYW1lKSkpICMgUmVtb3ZlIG9pZ2luYWwgbmFtZXMgZnJvbSB0aGUgYWxpYXMNCmBgYA0KDQpgYGB7ciBmaWcud2lkdGg9MTF9DQojIFdobyBoYXMgdGhlIG1vc3QgYWxpYXNlcz8gKHNob3dpbmcgdGhlIG9uZXMgKHdpdGggYXQgbGVhc3QgNSBhbGlhc2VzKQ0KbG9uZ19uYW1lcyAlPiUgDQogIGZpbHRlcihhbGlhc19sZW5ndGggPj0gNSkgJT4lIA0KICBnZ3Bsb3QoKSArDQogICAgYWVzKHkgPSBhbGlhc19sZW5ndGgsIHggPSBmY3RfcmVvcmRlcihuYW1lLCBhbGlhc19sZW5ndGgpKSArDQogICAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogICAgc2NhbGVfeF9kaXNjcmV0ZSgpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnMoeSA9ICJOdW1iZXIgb2YgYWxpYXNlcyIsIHggPSAiTmFtZSIpICsNCiAgICBnZ3RpdGxlKCJDaGFyYWN0ZXJzIHdpdGggdGhlIG1vc3QgYWxpYXNlcyAoYWwgbGVhc3QgNSkiKQ0KYGBgDQoNCg0KPGNlbnRlcj4NCiFbXShodHRwczovL21lZGlhLmdpcGh5LmNvbS9tZWRpYS9zRGtWM2NHZ1dLdFI2L2dpcGh5LmdpZikNCjwvY2VudGVyPg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBmaWcuYWxpZ249ImNlbnRlciIsbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQ3JlYXRlIGEgd29yZGNsb3VkIG9mIHRoZSBhbGlhc2VzDQpsb25nX25hbWVzICU+JSANCiAgYW50aV9qb2luKHN0b3Bfd29yZHMsIGJ5ID0gIndvcmQiKSAlPiUgIyBSZW1vdmUgc3RvcHdvcmRzDQogIGdyb3VwX2J5KHdvcmQpICU+JSANCiAgY291bnQoKSAlPiUgDQogIHdvcmRjbG91ZDIoKQ0KYGBgDQoNCmBgYHtyIGZpZy53aWR0aD0xMX0NCiMgU2hvdyB0aGUgY2hhcmFjdGVyIGFsaWFzIHNlbnRpbWVudHMNCmxvbmdfbmFtZXMgJT4lIA0KICBhbnRpX2pvaW4oc3RvcF93b3JkcywgYnkgPSAid29yZCIpICU+JSANCiAgZHJvcF9uYShzZW50aW1lbnQpICU+JSANCiAgZ3JvdXBfYnkobmFtZSwgc2VudGltZW50KSAlPiUgDQogIHN1bW1hcmlzZShmdWxsX2FsaWFzID0gcGFzdGUod29yZCwgY29sbGFwc2UgPSAiICIpLA0KICAgICAgICAgICAgYWxpYXNfbGVuZ3RoID0gZmlyc3QoYWxpYXNfbGVuZ3RoKSwNCiAgICAgICAgICAgIHNlbnRpbWVudF9uID0gbigpKSAlPiUgDQogIGZpbHRlcihzZW50aW1lbnRfbj4xKSAlPiUgDQogIGFycmFuZ2UoLWFsaWFzX2xlbmd0aCkgJT4lIA0KICBnZ3Bsb3QoKSArDQogICAgYWVzKHggPSBmY3RfcmVvcmRlcihuYW1lLCBzZW50aW1lbnRfbiksIHkgPSBzZW50aW1lbnRfbiwgZmlsbCA9IHNlbnRpbWVudCwgbGFiZWwgPSBmdWxsX2FsaWFzKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgZ2VvbV90ZXh0KGhqdXN0ID0gMSkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgbGFicyh5ID0gIk51bWJlciBvZiBhbGlhc2VzIHdpdGggc2VudGltZW50IiwgeCA9ICJOYW1lIikgKw0KICAgIGdndGl0bGUoIlNlbnRpbWVudCBvZiB0aGUgYWxpYXNlcyBieSBuYW1lIikNCmBgYA0KDQpTbywgd2UgY2FuIGNvbmNsdWRlIHRoYXQgdGhlIFR5cmlvbiBMZW5uaXN0ZXIsIFJhbXNleSBTbm93LCBKb24gU25vdywgYW5kIEJyYW5kb24gU3RhcmsgaGFzIHRoZSBtb3N0IGFsaWFzZXMgd2l0aCBuZWdhdGl2ZSBjb25ub3RhdGlvbnMuIEhvbmVzdGx5IEkgdGhpbmsgdGhhdCB0aGUgc3RhbmRhcmQgc2VudGltZW50IGxpYnJhcnkgaXMgbm90IHBlcmZlY3RseSBzdWl0YWJsZSBmb3IgdGhpcyBqb2IgYXMgaXQgZG9lcyBub3QgY29udGFpbiBzZW50aW1lbnRzIGZvciAia2luZyBzbGF5ZXIiLCAic2lsdmVyIHRvbmd1ZSIsIG9yICJob3JzZSBmYWNlIi4gU28gYSBtb3JlIHN1aXRhYmxlIHNlbnRpbWVudCBsaWJyYXJ5IHNob3VsZCBiZSB1c2VkIHRvIGltcHJvdmUgdGhlIGFjY3VyYWN5IG9mIHRoaXMgYW5hbHlzaXMuDQoNCjxjZW50ZXI+DQohW10oaHR0cHM6Ly9tZWRpYS5naXBoeS5jb20vbWVkaWEvUXk4REpESGFDQjJqQy9naXBoeS5naWYpDQo8L2NlbnRlcj4NCg0KIyBBbmFseXNpcyBxdWVzdGlvbiAyOiBFeHBsb3Jpbmcgc3Vydml2YWwgY2hhbmNlIG9mIGdvdCBjaGFyYWN0ZXJzDQoNCkJhc2VkIG9uIHRoZSBkYXRhIG9mIDU4NSBjaGFyYWN0ZXJzIHdob3NlIGRlYXRoIHdhcyBkb2N1bWVudGVkIGluIGdvdCwgaXQgc2VlbXMgbGlrZSBtYWxlcyBoYXZlIGEgaGlnaGVyIGhpZ2hlciBhZ2UgYXQgZGVhdGggKG1lYW4gPSAzNi41LCBTRCA9IDIyLjcpIHRoYW4gZmVtYWxlcyAobWVhbiA9IDI4LjIgU0QgPSAxNi41KS4gTm90IHRoYXQgaGlnaC4gQWxzbywgbWFsZXMgZXhwZWN0ZWQgYWdlIG9mIGRlYXRoIGlzIGJhc2VkIG9uIGFsbW9zdCA1IHRpbWVzIGFzIG1hbnkgb2JzZXJ2YXRpb25zLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZ290X2NoYXJzX2RmICU+JSANCiAgZmlsdGVyKCFpc19hbGl2ZSkgJT4lIA0KICBncm91cF9ieShnZW5kZXIpICU+JSANCiAgc3VtbWFyaXNlKE1lYW4gPSBtZWFuKGFnZSwgbmEucm0gPSBUKSAlPiUgcm91bmQoMSksDQogICAgICAgICAgICBTZCA9IHNkKGFnZSwgbmEucm0gPSBUKSAlPiUgcm91bmQoMSksDQogICAgICAgICAgICBOID0gbigpKQ0KDQpnb3RfY2hhcnNfZGYgJT4lIA0KICBmaWx0ZXIoIWlzX2FsaXZlKSAlPiUgDQogIGdncGxvdCgpICsNCiAgICBhZXMoeCA9IGFnZSwgeSA9IGdlbmRlciwgZmlsbCA9IGdlbmRlcikgKw0KICAgIGdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGEgPSAuNykNCmBgYA0KDQoNCiMgU28gaG93IGRhbmdlcm91cyBpcyBhIG1hcnJpYWdlIGluIEdPVD8gDQoNCjxjZW50ZXI+DQohW10oaHR0cHM6Ly9tZWRpYS5naXBoeS5jb20vbWVkaWEvU3RBTEF0TW1FM01KTy9naXBoeS5naWYpDQo8L2NlbnRlcj4NCg0KUGVvcGxlIGRpZSBsZWZ0IGFuZCByaWdodCBpbiBnYW1lIG9mIHRocm9uZXMsIGJ1dCBubyBvY2Nhc2lvbiBpcyBhcyBkZWFkbHkgYXMgYSBnb29kIHdlZGRpbmcuIEJ1dCB3aGF0IGFib3V0IG1hcnJpYWdlPyBIb3cgcGVvcGxlIGZhcmUgaWYgdGhleSBzdXJ2aXZlZCB0aGVpciB3ZWRkaW5nPyBJbiByZWFsIGxpZmUsIGxpZmV0aW1lIGV4cGVjdGFuY3kgaXMgaW5jcmVhc2VkIGJ5IG1hcnJpYWdlLCB3aGljaCBpcyBvYnZpb3VzbHkgbm90IHRoZSBjYXNlIGluIEdhbWUgb2YgVGhyb25lcy4gQnV0IGV4YWN0bHkgaG93IGRhbmdlcm91cyBpcyB0byBiZSBtYXJyaWVkIGluIEdPVD8gDQoNCldlIGFyZSBidWlsZGluZyBhIGxvZ2lzdGljIGJpbm9taWFsIHJlZ3Jlc3Npb24gb24gZ290IGNoYXJhY3RlciBkYXRhIHdpdGggdGhlIG91dGNvbWUgdmFyaWFibGUgdGhhdCBzaG93cyBpZiB0aGUgY2hhcmFjdGVyIGlzIGFsaXZlIG9yIG5vdC4gDQpXZSByZXN0cmljdCB0aGUgYW5hbHlzaXMgdG8gY2hhcmFjdGVycyB0aGF0IHdlcmUgYm9ybiB3aXRoaW4gYSAxMDIgeWVhcnMgKFRoaXMgaXMgdGhlIGFnZSBvZiBvbGRlc3QgY2hhcmFjdGVyIHRoYXQgZGllcyBpbiB0aGUgYm9va3MpIGJlY2F1c2Ugd2Ugd2FudCB0byBmb2N1cyBvbiB0aGUgYm9vaydzIHN0b3J5LWxpbmUuIFdlIGFyZSBvbmx5IGxvb2tpbmcgZm9yIG1haW4gZWZmZWN0cyBvZiBhZ2UsIGdlbmRlciwgYW5kIG1hcml0YWwgc3RhdHVzIChpZiB0aGUgY2hhcmFjdGVyIGhhcyBhIHNwb3VzZSkuIA0KRGlzY2xhaW1lcjogVGhpcyBpcyBvYnZpb3VzbHkgYSB2ZXJ5IHNpbXBsZSBtaW5kZWQgYW5hbHlzaXMsIGFuZCBJIG9ubHkgZGlkIHRoYXQgdG8gc2hvdyBob3cgdGhpcyBraW5kIG9mIHN0dWZmIGNhbiBiZSBkb25lIGluIFIuDQoNCmBgYHtyfQ0KZ290X2NoYXJzX2RmICU+JSANCiAgICBmaWx0ZXIoYmlydGhfeWVhciA+PTE5OCkgJT4lICMgUmVzdHJpY3QgYW5hbHlzaXMgdG8gcmVjZW50IGV2ZW50cyBpbiBnb3QgKGxhc3QgMTAyIHllYXJzKQ0KICAgIHNlbGVjdChpc19hbGl2ZSwgaGFzX3Nwb3VzZSwgZ2VuZGVyKSAlPiUgDQogICAgZnRhYmxlKCkNCmBgYA0KDQpUaGUgZGF0YSBpcyBiYXNlZCBvbiAzODYgY2hhcmFjdGVycywgd2l0aCB0aGUgY2hhcmFjdGVyaXN0aWNzIGFib3ZlLiANClRvIGV4cGxvcmUgZGF0YSwgd2UgY3JlYXRlIGEgYm94IHBsb3QgdmlzdWFsaXphdGlvbiBhYm91dCBhZ2UgYnkgZ2VuZGVyIGJ5IG1hcml0YWwgc3RhdHVzIGJ5IHN1cnZpdmFsIHN0YXR1cy4NCg0KYGBge3J9DQpnb3RfY2hhcnNfZGYgJT4lIA0KICAgIGZpbHRlcihiaXJ0aF95ZWFyID49MTk4KSAlPiUgIyBSZXN0cmljdCBhbmFseXNpcyB0byByZWNlbnQgZXZlbnRzIGluIGdvdCAobGFzdCAxMDIgeWVhcnMpDQogICAgZ2dwbG90KCkgKw0KICAgICAgYWVzKHkgPSBhZ2UsIHggPSBnZW5kZXIsIGZpbGwgPSBnZW5kZXIpICsNCiAgICAgIGdlb21fYm94cGxvdCgpICsNCiAgICAgIGZhY2V0X2dyaWQoaXNfYWxpdmV+aGFzX3Nwb3VzZSwgbGFiZWxsZXIgPSBsYWJlbF9ib3RoKQ0KYGBgDQoNCg0KTm93IHdlIGNyZWF0ZSBhIHN0YXRpc3RpY2FsIG1vZGVsIChiaW5vbWlhbCBsb2dpc3RpYykgdG8gdGVzdCB0aGUgZWZmZWN0IG9mIHRoZSBwcmVkaWN0b3JzIG9uIHRoZSBvdXRjb21lIHZhcmlhYmxlIChzdXJ2aXZhbCBzdGF0dXMpLg0KDQpgYGB7cn0NCnN1cnZpdmFsX21vZGVsIDwtDQogIGdvdF9jaGFyc19kZiAlPiUgDQogIGZpbHRlcihiaXJ0aF95ZWFyID49MTk4KSAlPiUgDQogICAgICBnbG0oaXNfYWxpdmUgfiBhZ2UgKyBoYXNfc3BvdXNlICsgZ2VuZGVyLCBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLikgDQoNCnN1cnZpdmFsX21vZGVsICU+JSBzdW1tYXJ5DQoNCmBgYA0KDQpNYWtlc2hpZnQgY29uY2x1c2lvbnM6DQoNCi0gV2UgbG9va2VkIGF0IGR5aW5nIGluIHRoZSBsYXN0IDEwMiB5ZWFycywgc28gd2UgZXhjbHVkZWQgY2hhcmFjdGVycyB3aG8gZGllZCBsb25nIGJlZm9yZSB0aGUgc3RvcnktbGluZSANCi0gQWdlIGlzIG5vdCBhIHNpZ25pZmljYW50IHByZWRpY3RvciBmb3IgZHlpbmcsIHNvIHBlb3BsZSBvZiBhbGwgYWdlcyBwZXJpc2ggbGVmdCBhbmQgcmlnaHQNCi0gTWFsZXMgaGF2ZSBhIHdvcnNlIHN1cnZpdmFsIGNoYW5jZSAodGhleSBhcmUgIHR3aWNlIGFzIGxpa2VseSB0byBkaWUgaW4gdGhlIGJvb2tzJyBzdG9yeS1saW5lKS4gVGhpcyBpcyB0aGUgb3Bwb3NpdGUgdG8gdGhlIHByZXZpb3VzIGZpbmRpbmcgYmVjYXVzZSBoZXJlIHdlIG9ubHkgZm9jdXNlZCBvbiByZWNlbnQgZXZlbnRzIHRoYXQgc2VlbSB0byBhZmZlY3QgbWFsZSBsaWZlIGV4cGVjdGFuY3kgbW9yZS4NCi0gTWFycmlhZ2UgaXMgcXVpdGUgZGFuZ2Vyb3VzIGluIEdPVCwgdGhlIHN1cnZpdmFsIHJhdGUgb2YgbWFycmllZCBwZW9wbGUgaXMgbGVzcyB0aGFuIGhhbGYgb2YgdW5tYXJyaWVkIG9uZXMuIA0KDQogV2UgYWxzbyBjYWxjdWxhdGUgb2RkcyByYXRpb3MsIGFuZCBjb25maWRlbmNlIGludGVydmFscyBmb3IgdGhvc2UgZm9yIHZpc3VhbGl6YXRpb24gb2YgZWZmZWN0cy4NCmBgYHtyIGZpZy53aWR0aD0xMSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnN1cnZpdmFsX29yIDwtIA0KZXhwKGNiaW5kKGNvZWYoc3Vydml2YWxfbW9kZWwpLCBjb25maW50KHN1cnZpdmFsX21vZGVsKSkpICU+JSANCiAgcm91bmQoMikgJT4lIA0KICBicm9vbTo6dGlkeSgpICU+JSANCiAgc2V0X25hbWVzKGMoInZhcmlhYmxlIiwgIk9SIiwiMi41JSBDSSIsIjk3LjUlIENJIikpDQoNCnN1cnZpdmFsX29yICU+JSANCiAgZ2dwbG90KCkgKw0KICAgIGFlcyh4ID0gT1IsIHkgPSBmY3RfcmV2KHZhcmlhYmxlKSwgeG1pbiA9IGAyLjUlIENJYCwgeG1heCA9IGA5Ny41JSBDSWAsIGxhYmVsID0gT1IpICsNCiAgICBnZW9tX2xhYmVsKGFlcyh4ID0gMCkpICsgIA0KICAgIGdlb21fZXJyb3JiYXJoKGhlaWdodCA9IDApICsNCiAgICBnZW9tX3BvaW50KCkgKw0KICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSAxKSwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICAgIGNvb3JkX2NhcnRlc2lhbihjKDAsNy41KSkgKw0KICAgIGxhYnMoeCA9ICJPZGRzIHJhdGlvICg5NSUgQ0kpIiwgeSA9IE5VTEwpICsNCiAgICBnZ3RpdGxlKCJPZGRzIHJhdGlvcyBmb3IgdmFyaWFibGVzIHRoYXQgcHJlZGljdCBzdXJ2aXZhbCBpbiBnb3QiKQ0KDQpgYGANCg0KQW5kIGZpbmFsbHksIGxldCdzIHBsb3QgdGhlIHByZWRpY3Rpb25zIGZvciB0aGUgc3Vydml2YWwgY2hhbmNlIG92ZXIgdGltZSBieSBtYXJpdGFsIHN0YXR1cyBhbmQgZ2VuZGVyLg0KDQpgYGB7ciBmaWcud2lkdGg9OSwgd2FybmluZz1GQUxTRX0NCnN1cnZpdmFsX21vZGVsICU+JSANCiAgICBicm9vbTo6YXVnbWVudCh0eXBlLnByZWRpY3QgPSAicmVzcG9uc2UiKSAlPiUgDQogICAgZ2dwbG90KCkgKw0KICAgIGFlcyh4ID0gYWdlLCB5ID0gLmZpdHRlZCwgZ3JvdXAgPSBoYXNfc3BvdXNlLCB5bWluID0gLmZpdHRlZCAtIC5zZS5maXQsIHltYXggPSAuZml0dGVkICsgLnNlLmZpdCkgKw0KICAgIGdlb21fcmliYm9uKGZpbGwgPSAiZ3JleSIsIGFscGhhID0gLjMpICsNCiAgICBmYWNldF93cmFwKH5nZW5kZXIpICsNCiAgICBnZW9tX3N0ZXAoYWVzKGNvbG9yID0gaGFzX3Nwb3VzZSksIHNpemUgPSAxLjIpICsNCiAgICBsYWJzKHggPSAiQWdlIiwgDQogICAgICAgICB5ID0gIlByZWRpY3RlZCBzdXJ2aXZhbCBjaGFuY2UgKE9SKSIsIA0KICAgICAgICAgdGl0bGUgPSAiUHJlZGljdGVkIHN1cnZpdmFsIGNoYW5jZSBhcyBhIGZ1bmN0aW9uIG9mIGFnZSwgZ2VuZGVyLCBhbmQgbWFyaXRhbCBzdGF0dXMgaW4gR2FtZSBvZiBUaHJvbmVzLFxuZHVyaW5nIHRoZSBzdG9yeWxpbmUgb2YgdGhlIGJvb2tzIikNCmBgYA0KDQo8Y2VudGVyPg0KIVtdKGh0dHBzOi8vbWVkaWEuZ2lwaHkuY29tL21lZGlhL29ob28wMzMwc1VsVHEvZ2lwaHkuZ2lmKQ0KPC9jZW50ZXI+DQoNCg==